﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Hammock;
using Hammock.Authentication.OAuth;
using Hammock.Web;
using Newtonsoft.Json.Linq;
using WeiboPlus.Models;
using WeiboPlus.Service;
using WeiboPlus.Service.Web;
using WeiboPlus.Tencent;

namespace WeiboPlus.Tencent
{
    public class TencentStatusService : StatusServiceBase
    {
        protected override RestClient CreateRestClient()
        {
            return new RestClient
                {
                    Authority = "http://open.t.qq.com",   // Tencent调用API的时候不是用的https协议，这点和获取Token方式不同
                    HasElevatedPermissions = true
                };
        }

        protected override IList<SNSStatus> Mapping(string res,SNSResult result)
        {
            JObject o = JObject.Parse(res);

            List<SNSStatus> statuses = o.SelectToken("data.info").Select(
                s => Factory.GetMapping<JToken, SNSStatus>().Map(s)
                ).ToList();
            return statuses;
        }

        protected override IList<T1> Mapping<T1>(string res, SNSResult result)
        {
            JObject o = JObject.Parse(res);

            List<T1> list = o.SelectToken("data.info").Select(
                s => Factory.GetMapping<JToken, T1>().Map(s)
                ).ToList();
            return list;
        }

        protected override Hammock.Authentication.IWebCredentials CreateCredential()
        {
            var credantial = base.CreateCredential() as OAuthCredentials;
            credantial.ParameterHandling = OAuthParameterHandling.UrlOrPostParameters;
            return credantial;
        }

        protected override string[] GetParamtersList(SNSType type)
        {
            switch (type)
            {
                case SNSType.MentionsStatus:
                case SNSType.PublicStatus:
                case SNSType.HomeStatus:
                    return new string[] {
                        SNSParametersConstants.PAGE_TIME, 
                        SNSParametersConstants.REQ_NUM, 
                        SNSParametersConstants.PAGE_FLAG,
                        SNSParametersConstants.TYPE, 
                        SNSParametersConstants.CONTENTTYPE, 
                        SNSParametersConstants.ACCESSLEVEL
                    };

                case SNSType.SearchStatus:
                    return new string[] { 
                        SNSParametersConstants.KEY_WORD, 
                        SNSParametersConstants.PAGE_SIZE, 
                        SNSParametersConstants.PAGE
                    };

                case SNSType.AddStatus:
                    return new string[] {
                        SNSParametersConstants.CONTENT,
                        SNSParametersConstants.CLIENT_IP, 
                        SNSParametersConstants.FORMAT,
                        SNSParametersConstants.JING, 
                        SNSParametersConstants.WEI 
                    };
                case SNSType.Upload:
                    return new string[] {
                        SNSParametersConstants.CONTENT,
                        SNSParametersConstants.CLIENT_IP, 
                        SNSParametersConstants.FORMAT,
                        SNSParametersConstants.JING, 
                        SNSParametersConstants.WEI ,
                        SNSParametersConstants.PIC
                    };
                case SNSType.RepostStatus:
                    return new string[] { 
                        SNSParametersConstants.CONTENT, 
                        SNSParametersConstants.CLIENT_IP, 
                        SNSParametersConstants.JING, 
                        SNSParametersConstants.WEI, 
                        SNSParametersConstants.REID 
                    };

                case SNSType.CommentsToMe:
                    return new string[] {
                        SNSParametersConstants.PAGE_TIME, 
                        SNSParametersConstants.REQ_NUM, 
                        SNSParametersConstants.PAGE_FLAG,
                        SNSParametersConstants.TYPE, 
                        SNSParametersConstants.LAST_ID,
                        SNSParametersConstants.CONTENTTYPE,
                        SNSParametersConstants.ACCESSLEVEL 
                    };

                case SNSType.CommentsByMe:
                    return new string[] {
                        SNSParametersConstants.PAGE_TIME, 
                        SNSParametersConstants.REQ_NUM, 
                        SNSParametersConstants.PAGE_FLAG,
                        SNSParametersConstants.TYPE,
                        SNSParametersConstants.LAST_ID,
                        SNSParametersConstants.CONTENTTYPE,
                        SNSParametersConstants.ACCESSLEVEL
                    };

                case SNSType.CommentsByID:
                    return new string[] { 
                        SNSParametersConstants.FLAG,
                        SNSParametersConstants.ROOTID,
                        SNSParametersConstants.PAGE_FLAG,
                        SNSParametersConstants.PAGE_TIME,
                        SNSParametersConstants.REQ_NUM,
                        SNSParametersConstants.TWITTERID
                    };

                case SNSType.AddComment:
                    return new string[]
                    { 
                        SNSParametersConstants.CONTENT,
                        SNSParametersConstants.CLIENT_IP,
                        SNSParametersConstants.JING,
                        SNSParametersConstants.WEI,
                        SNSParametersConstants.REID
                    };

                case SNSType.DeleteComment:
                    return new string[] { 
                        //SNSParametersConstants.COUNT,
                        //SNSParametersConstants.BASE_APP
                    };

                case SNSType.UserStatus:
                    return new string[] {
                        SNSParametersConstants.PAGE_FLAG,
                        SNSParametersConstants.PAGE_TIME, 
                        SNSParametersConstants.REQ_NUM, 
                        SNSParametersConstants.NAME,
                        SNSParametersConstants.TYPE,
                    };
                case SNSType.ResetCount:
                    return new string[] {
                        SNSParametersConstants.OP,
                        SNSParametersConstants.TYPE
                    };
                case SNSType.QueryCount:
                    return new string[]
                    {
                        SNSParametersConstants.OP
                    };
                default:

                    return new string[] { };
            }
        }

        protected int ValidateResponse(string content, out string msg)
        {
            //return base.ValidateResponse(o, out msg);
            //o.Content
            var jo = JObject.Parse(content);
            if (jo == null)
            {
                msg = "object type no match";
                return 0;
            }

            //TO-DO ERROE HANDLE
            var errcode = (int)jo.SelectToken("errcode");
            var ret = (int)jo.SelectToken("ret");

            if (jo.SelectToken("data.pageinfo") != null)
                msg = "pageinfo|" + (string)jo.SelectToken("data.pageinfo");
            else
                msg = (string)jo.SelectToken("msg");

            bool isvalid = errcode == 0 && ret == 0 && !msg.Contains("have no") && !msg.Contains("result is empty");

            if (msg.Contains("have no") || msg.Contains("result is empty"))
                return 99;

            if (isvalid)
                return 1;
            else
                return 0;
        }

        protected override int ValidateResponse(RestResponse o, out string msg)
        {
            //return base.ValidateResponse(o, out msg);
            //o.Content
            if (o.Content.StartsWith("<"))
            {
                msg = o.Content;
                return 0;
            }

            var jo = JObject.Parse(o.Content);
            if (jo == null)
            {
                msg = "object type no match";
                return 0;
            }

            //TO-DO ERROE HANDLE
            int errcode = 0, ret = 0;
            if (jo.SelectToken("errcode") != null)
                errcode = (int)jo.SelectToken("errcode");
            if (jo.SelectToken("errcode") != null)
                ret = (int)jo.SelectToken("ret");

            if (jo.SelectToken("data.pageinfo") != null)
                msg = "pageinfo|" + (string)jo.SelectToken("data.pageinfo");
            else
                msg = (string)jo.SelectToken("msg");

            bool isvalid = errcode == 0 && ret == 0 && !msg.Contains("have no") && !msg.Contains("result is empty");

            if (msg.Contains("have no") || msg.Contains("result is empty"))
                return 99;

            if (isvalid)
                return 1;
            else
                return 0;
        }

        protected override void Initialize()
        {
            STATUS_HOME_TIMELINE = "/api/statuses/home_timeline?format=json&";
            STATUS_MENTIONS_TIMELINE = "/api/statuses/mentions_timeline?format=json&";

            STATUS_USER_TIMELINE = "/api/statuses/user_timeline?format=json&";
            STATUS_SEARCH_TIMELINE = "/api/search/t?format=json&";
            STATUS_UPDATE = "/api/t/add";
            STATUS_UPLOAD = "/api/t/add_pic";
            STATUS_REPOST = "/api/t/re_add";
            STATUS_REPLY = "/api/t/comment";
            COMMENT_BY_ME = "/api/statuses/broadcast_timeline?format=json&";
            COMMENT_TO_ME = "/api/statuses/mentions_timeline?format=json&";
            COMMENT_BY_ID = "/api/t/re_list?format=json&";
            COMMENT_ADD = "/api/t/comment?format=json&";
            COMMENT_DELETE = "statuses/comment_destroy/:id.json";

            QUERY_COUNT = "/api/info/update?format=json&";
            RESET_COUNT = "/api/info/update?format=json&";
        }

        public override void UpdateStatus(SNSRequest snsRequest, Action<SNSStatus, SNSResult> action)
        {
            if (!TryMappingMethodString(snsRequest))
            {
                //TO-DO
            }
            List<SNSParameter> file = null;
            var pList = GetParamtersList(snsRequest.Type);
            snsRequest.Predicate = (p) => pList.Contains(p.Name);

            var paras = new List<SNSParameter>(snsRequest.Parameters.Where(snsRequest.Predicate));

            var request = new QWeiboRequest();
            int key = 0;
            if (paras.Any(p => p.Style == ParameterStyle.FilePath && p.Name == SNSParametersConstants.PIC))
            {
                var files = paras.Where(p => p.Style == ParameterStyle.FilePath).ToList();
                foreach (var f in files)
                {
                    paras.Remove(f);
                }
                file = new List<SNSParameter>(files).ToList();
            }


            request.BeginAsyncPost("http://open.t.qq.com" + snsRequest.Method, "POST", new OauthKey(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET) { tokenKey = Account.AccessToken, tokenSecret = Account.AccessTokenSecret }, paras, file, (k, content) =>
            {
                try
                {
                    Helper.Log("End request at " + DateTime.Now.ToShortTimeString());
                    Helper.Log(content.ToString());

                    string msg = "";
                    int isvalid = ValidateResponse(content, out msg);

                    if (isvalid > 0)
                    {
                        var s = MappingSingle(content);
                        if (s != null)
                        {
                            s.Text = snsRequest.Parameters.Where((p) => { return p.Name == SNSParametersConstants.STATUS_TEXT; }).FirstOrDefault().Value;
                            //s.User = Account.UserLite;
                        }

                        action(s, new SNSResult() { IsSuccess = true, Message = msg });
                    }
                    else
                    {
                        throw new Exception(msg);
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
                }
            }, out key);


        }

        protected override T MappingSingle<T>(string res, SNSResult result)
        {
            JObject o = JObject.Parse(res);
            var msg = o.SelectToken("msg");


            if (msg != null && (string)msg == "ok")
            {
                var t = Factory.GetMapping<JToken, T>().Map(o.SelectToken("data"));

                return t;
            }
            else
            {
                return null;
            }
        }

        protected SNSStatus MappingSingle(string content)
        {
            JObject o = JObject.Parse(content);
            var msg = o.SelectToken("msg");


            if (msg != null && (string)msg == "ok")
            {
                var status = Factory.GetMapping<JToken, SNSStatus>().Map(o.SelectToken("data"));

                return status;
            }
            else
            {
                return null;
            }
        }

        protected override SNSStatus MappingSingle(string res,SNSResult result)
        {
            JObject o = JObject.Parse(res);
            var msg = o.SelectToken("msg");


            if (msg != null && (string)msg == "ok")
            {
                var status = Factory.GetMapping<JToken, SNSStatus>().Map(o.SelectToken("data"));

                return status;
            }
            else
            {
                return null;
            }
        }

        public override void AddComment(SNSRequest request, Action<SNSStatus, SNSResult> action)
        {
            base.AddComment(request, (comment, result) =>
            {
                if (comment != null && string.IsNullOrEmpty(comment.Text))
                {
                    comment.Text = request.Parameters.Where(p => p.Name == SNSParametersConstants.CONTENT).First().Value;
                }
                if (action != null)
                {
                    action(comment, result);
                }
            });
        }

        protected override void PerformRequest<T1>(Action<IList<T1>, SNSResult> action, SNSRequest snsRequest)
        {
            base.PerformRequest<T1>(new Action<IList<T1>, SNSResult>((list, result) =>
            {
                var msg = result.Message;
                if (result.IsSuccess && msg.Contains("pageinfo"))
                {
                    result.PagingInfo = new SNSPagingInfo()
                    {
                        PageInfo = msg.Substring(msg.LastIndexOf('|') + 1)
                    };
                }
                action(list, result);

            }), snsRequest);
        }
    }
}
